﻿#include "threshold.hpp"
#include "utility.hpp"

namespace cuda
{
__global__
void __threshold(float2* src, float2* dst, int nRows, int nCols, const float __Lambda)
{
	/// <summary>	Shared Memory Declaration</summary>
	extern __shared__ float2 shared[];
	float square;
	float absolute;
// 	float Lambda;
// 	float scale;
	/// <summary>	Copy a block to Shared Memory from global memory </summary>
  	shared[threadIdx.x].x		= src[(nRows|nCols)*blockIdx.x + threadIdx.x].x;
	shared[threadIdx.x].y		= src[(nRows|nCols)*blockIdx.x + threadIdx.x].y;
	__syncthreads();

 	/// <summary>	Calculate the absolute value </summary>
	square = shared[threadIdx.x].x * shared[threadIdx.x].x
             + shared[threadIdx.x].y * shared[threadIdx.x].y; 
	//printf("%5.10f \t %4.3f\n", absolute, __Lambda);
	__syncthreads();
	absolute = sqrtf(square);
	__syncthreads();
//  	shared[threadIdx.x].z	= shared[threadIdx.x].x * shared[threadIdx.x].x
//  							+ shared[threadIdx.x].y * shared[threadIdx.x].y;
//   	__syncthreads();
//  	shared[threadIdx.x].z	= sqrtf(shared[threadIdx.x].z);
//  	__syncthreads();	
	
	/// <summary>	Perform Soft Thresholding </summary>
	//printf("%5.10f \t %4.3f\n", absolute, __Lambda);
 	if(absolute > __Lambda)
 	{		
		shared[threadIdx.x].x = shared[threadIdx.x].x*(absolute-__Lambda)/absolute;
		shared[threadIdx.x].y = shared[threadIdx.x].y*(absolute-__Lambda)/absolute;
		__syncthreads();
		//printf("%5.10f \t %4.3f\n", shared[threadIdx.x].x, __Lambda);
 		/// <summary>	Write back from Shared Memory to global memory</summary>
  		dst[(nRows|nCols)*blockIdx.x + threadIdx.x].x	= shared[threadIdx.x].x;
 		dst[(nRows|nCols)*blockIdx.x + threadIdx.x].y	= shared[threadIdx.x].y;
		//printf("%4.3f \n", shared[threadIdx.x].x);
 	}
 	else
 	{	
		//printf("Less than Lambda \n");
 		/// <summary>	Write back from Shared Memory to global memory</summary>
  		dst[(nRows|nCols)*blockIdx.x + threadIdx.x].x	= 0.0f;
 		dst[(nRows|nCols)*blockIdx.x + threadIdx.x].y	= 0.0f;
 	}
}
void threshold(float2* src, float2* dst, int nRows, int nCols, const float Lambda)
{
	/// <summary>	Copy Lambda to constant memory </summary>

	/// <summary>	Kernel Configuration</summary>
	dim3 nBlocks(nRows|nCols);
 	dim3 nThreads(nRows|nCols);
	/// <summary>	Kernel Launching</summary>
	__threshold<<<nBlocks, nThreads, (nRows|nCols)*sizeof(float2)>>>
					(src, dst, nRows, nCols, Lambda);
	cudaThreadSynchronize();
	cudaGetLastError();
}
}


